package com.quectel.cms.controller.pay;

import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.vo.pay.PayRefundReq;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.pay.module.order.constants.OrderConstants;
import com.quectel.pay.module.order.constants.OrderRefundConstants;
import com.quectel.pay.module.order.dto.PayOrderDto;
import com.quectel.pay.module.order.dto.PayOrderRefundDto;
import com.quectel.pay.module.order.service.PayOrderRefundService;
import com.quectel.pay.module.order.service.PayOrderService;
import com.quectel.util.common.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static com.quectel.constant.global.StatisticsConstants.TIME_RANGE_BY_DAY;

/**
 * 在这里编写说明
 *
 * @author: ryan
 * @email: ryan.ran@quectel.com
 * @date: 2023-05-26 14:34:00
 */
@RestController
@RequestMapping("payOrder")
@Tag(name = "PayOrderController", description = "支付中心支付账单相关api")

public class PayOrderController extends BaseController {

    @DubboReference
    private PayOrderService payOrderService;
    @DubboReference
    private VillageService villageService;
    @DubboReference
    private PayOrderRefundService payOrderRefundService;

    @PostMapping("refund")
    @RequirePermissions(values = "payOrder:refund")
    public Response<Object> refund(@RequestBody PayRefundReq payRefundReq) {
        PayOrderDto payOrderDto = payOrderService.selectById(payRefundReq.getOrderId());
        if (Objects.isNull(payOrderDto)) {
            return Response.error("订单不存在");
        }
        if (!OrderConstants.Status.PAY_SUCCESS.getStatusValue().equals(payOrderDto.getStatus())) {
            return Response.error("订单未支付成功");
        }
        PayOrderRefundDto newlyDto = new PayOrderRefundDto();
        newlyDto.setVillageId(payOrderDto.getVillageId());
        newlyDto.setOrderId(payOrderDto.getId());
        newlyDto.setOutTradeNo(payOrderDto.getOutTradeNo());
        newlyDto.setTotalAmount(payOrderDto.getSpecialPrice());
        newlyDto.setOutRefundNo(payOrderService.genOrderNo());
        newlyDto.setRefundAmount(payRefundReq.getRefundAmount());
        newlyDto.setRefundStatus(OrderRefundConstants.OrderRefundStatus.NOT_REFUND.getStatus());
        newlyDto.setRefundType(OrderRefundConstants.RefundType.PERSON.getType());
        newlyDto.setRefundNotifyUrl(payOrderDto.getRefundNotifyUrl());
        newlyDto.setAuditStatus(OrderRefundConstants.RefundAuditStatus.AUDIT.getStatus());
        fillSaveCommonData(newlyDto);
        payOrderRefundService.save(newlyDto);
        return Response.ok();
    }

    /**
     * 根据业务id获取通用账单
     * @param businessType 业务账单类型
     * @param businessId 业务账单id
     *
     * @return
     */
    @GetMapping("queryByBusiness")
    public Response<List<PayOrderDto>> queryByBusiness(
            @Parameter(description = "业务类型") @RequestParam String businessType,
            @Parameter(description = "业务账单id") @RequestParam Long businessId
    ){
        Request request = Request.configParamsNotPage(Request.parseParams(httpServletRequest));
        fillAuthorityDataByRegionOrVillageInMemory(request.getParams());

        request.put(LambdaUtil.getFieldName(PayOrderDto::getBusinessType), businessType);
        request.put(LambdaUtil.getFieldName(PayOrderDto::getBusinessId), businessId);

        List<PayOrderDto> payOrderDtos = payOrderService.queryList(request.getParams());

        Map<Long, VillageDto> villageCacheMap = new HashMap<>();
        for (PayOrderDto payOrderDto : payOrderDtos) {
            VillageDto village = villageCacheMap.computeIfAbsent(payOrderDto.getVillageId(), key -> villageService.selectCacheById(key));
            if (Objects.nonNull(village)) {
                payOrderDto.setVillageName(village.getName());
            }
            List<PayOrderRefundDto> refundDtos = payOrderRefundService.selectByOrderId(payOrderDto.getId());
            payOrderDto.setPayOrderRefunds(refundDtos);
        }
        return Response.<List<PayOrderDto>>ok().wrap(payOrderDtos);
    }

    /**
     * 列表
     */
    @GetMapping("exportExcel")
    @RequirePermissions(values = "payOrder:exportExcel")
    public void exportExcel(@RequestParam Map<String, Object> params, HttpServletResponse httpServletResponse) {
        String[] headers = new String[]{"所属小区", "产品名称", "商户订单号", "手机号", "支付类型", "终端类型", "业务类型", "原价", "支付金额", "状态", "支付时间"};
        List<String[]> dataList = new ArrayList<>();

        if (params.containsKey(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft())
                && params.containsKey(SystemConstants.TIME_SLOT_KEY_PAIR.getRight())
                && checkTimeRange(TIME_RANGE_BY_DAY, params.get(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft()) + ""
                , params.get(SystemConstants.TIME_SLOT_KEY_PAIR.getRight()) + "", 32).isSuccess()) {

            super.fillAuthorityDataByRegionOrVillageInMemory(params);

            List<PayOrderDto> result = new ArrayList<>();
            int pageNo = 0;
            params.put("limit", 1000);
            while (true) {
                params.put("offset", pageNo++ * 1000);
                List<PayOrderDto> list = payOrderService.queryList(params);
                if (CollectionUtils.isEmpty(list)) {
                    break;
                }
                result.addAll(list);
                if (list.size() < 1000) {
                    break;
                }
            }

            Map<Long, VillageDto> villageCacheMap = new HashMap<>();

            for (PayOrderDto data : result) {
                VillageDto village = villageCacheMap.computeIfAbsent(data.getVillageId(), key -> villageService.selectCacheById(key));
                String[] item = new String[headers.length];
                item[0] = Objects.nonNull(village) ? village.getName() : "";
                item[1] = data.getProductName();
                item[2] = data.getOutTradeNo();
                item[3] = data.getMobile();
                item[4] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PAY_TYPE, data.getPayType() + "");
                item[5] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.TERMINAL_TYPE, data.getTerminalType() + "");
                item[6] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.MERCHANT_BUSINESS_TYPE, data.getTerminalType() + "");
                item[7] = data.getOriginalPrice().toPlainString();
                item[8] = data.getSpecialPrice().toPlainString();
                item[9] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.PAY_STATUS, data.getStatus() + "");
                item[10] = Objects.nonNull(data.getPayTime()) ? DateUtils.format(data.getPayTime(), DateUtils.FormatType.COMMON) : "";
                dataList.add(item);
            }

            POIUtils.exportExcel(httpServletResponse, "支付账单信息", headers, dataList, "支付账单信息");
        }


    }

    /**
     * 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("list")
    @RequirePermissions(values = "payOrder:list")
    @Operation(summary = "分页列表")
    public Response<Page<PayOrderDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));
        Map<String, Object> params = request.getParams();

        if (params.containsKey(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft())
                && params.containsKey(SystemConstants.TIME_SLOT_KEY_PAIR.getRight())
                && checkTimeRange(TIME_RANGE_BY_DAY, params.get(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft()) + ""
                , params.get(SystemConstants.TIME_SLOT_KEY_PAIR.getRight()) + "", 32).isSuccess()) {
            super.fillAuthorityDataByRegionOrVillageInMemory(request.getParams());
            int total = payOrderService.queryTotal(request.getParams());

            List<PayOrderDto> list = null;
            if (total > 0) {
                list = payOrderService.queryList(request.getParams());
            } else {
                list = new ArrayList<>();
            }

            for (PayOrderDto payOrderDto : list) {
                VillageDto villageDto = villageService.selectCacheById(payOrderDto.getVillageId());
                if (Objects.nonNull(villageDto)) {
                    payOrderDto.setVillageName(villageDto.getName());
                }
            }

            Page<PayOrderDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
            return Response.<Page<PayOrderDto>>ok().wrap(page);
        }
        return Response.error("查询参数不正确");

    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "payOrder:info")
    @Operation(summary = "查询单条记录")
    public Response<PayOrderDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (payOrderService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PayOrderDto payOrderDto = payOrderService.selectById(id);
        if (Objects.nonNull(payOrderDto)) {
            VillageDto villageDto = villageService.selectCacheById(payOrderDto.getVillageId());
            if (Objects.nonNull(villageDto)) {
                payOrderDto.setVillageName(villageDto.getName());
            }
            List<PayOrderRefundDto> refundDtos = payOrderRefundService.selectByOrderId(payOrderDto.getId());
            payOrderDto.setPayOrderRefunds(refundDtos);
        }
        return Response.<PayOrderDto>ok().wrap(payOrderDto);
    }
}
